"""
CSPBuilder plugin

Does broadcast by using a Broadcast process and the neccessary One2One channels

Implements an Any2All functionality

See LICENSE.txt for licensing details (GPLv2).
Copyright (c) 2008 Rune M. Friborg, runef@diku.dk.
"""

PLUGIN_NAME = "Broadcast"

from extensions.containers import *
import copy
import os
from plugins.execute import *

class PluginBroadcast(PluginEXECUTION):

    def __init__(self, pluginManager):
        PluginEXECUTION.__init__(self, pluginManager, PLUGIN_NAME)

    def _check_broadcast(self, val):
        return (val == 'yes')

    def addBroadcastToReducedSet(self, channelObjList, processObjList): 
        i = 0
        channels_delete = []
        channels_add = []
        for channel in channelObjList:
            if channel.plugin_attr.has_key('broadcast') and self._check_broadcast(channel.plugin_attr['broadcast']):
                channels_delete.append(channel)

                cList = {'in':[],'out':[]}
                for c in channel.connectionObjList:
                    cList[c.direction].append(c)
                channelEndObjList = []
                
                j = 0
                for c in cList['out']:
                    one2one = ReducedChannelDef('bchan__out_'+str(i)+'_'+str(j), channel.plugin_attr)
                    one2one.connectionObjList.append(c)

                    chanEnd = 'in'+str(j)
                    channelEndObjList.append(ChannelEndDef('in', chanEnd))
                    one2one.connectionObjList.append(ConnectionDef('BroadcastProcess_'+str(i)+'.broadcastFunc.'+chanEnd, 'in'))
                    channels_add.append(one2one)
                    j += 1

                j = 0
                for c in cList['in']:
                    one2one = ReducedChannelDef('bchan_in_'+str(i)+'_'+str(j), channel.plugin_attr)
                    one2one.connectionObjList.append(c)

                    chanEnd = 'out'+str(j)
                    channelEndObjList.append(ChannelEndDef('out', chanEnd))
                    one2one.connectionObjList.append(ConnectionDef('BroadcastProcess_'+str(i)+'.broadcastFunc.'+chanEnd, 'out'))
                    
                    channels_add.append(one2one)
                    j += 1

                # Create codeObj
                filename = 'Broadcast'
                try:
                    funcName = 'broadcastFunc'
                    funcObj = __import__(filename).__dict__[funcName]
                except ImportError, value:
                    print 'Error: Code could not be loaded:', filename, 'at', os.getcwd()
                    print 'Error:', value
                    return ([],[])

                codeObj = CodeDef(funcName, funcObj, channelEndObjList)

                # Create a new Broadcast process
                processObjList.append(ProcessDef('BroadcastProcess_'+str(i), codeObj))

            i += 1
        
        # Delete replaced channels
        for x in channels_delete:
            del channelObjList[channelObjList.index(x)]

        # Add the replacements
        channelObjList.extend(channels_add)

        return (channelObjList, processObjList)

    def preserve(self, new_plugin_attr, old_plugin_attr):
        if old_plugin_attr.has_key('broadcast') and self._check_broadcast(old_plugin_attr['broadcast']):
            new_plugin_attr['broadcast'] = 'yes'


def load(pluginManager):

    p = PluginBroadcast(pluginManager)

    p.addPreserveAttributes(p.preserve)
    p.addReducedSetProcessor(p.addBroadcastToReducedSet)

    pluginManager.addPlugin(p)
